﻿using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Dispatcher.Extensions;
using Dispatcher.Views;
using Foundation;

namespace Dispatcher.Helpers
{
    /// <summary>
    /// Drag Drop List View Helper.
    /// </summary>
    public class ListViewDragDropHelper : ViewModel
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ListViewDragDropHelper"/> class.
        /// </summary>
        /// <param name="listView">The list view.</param>
        public ListViewDragDropHelper(CommonListView listView)
        {
            ListView = listView;
        }

        /// <summary>
        /// Gets or sets the list view.
        /// </summary>
        /// <value>
        /// The list view.
        /// </value>
        private CommonListView ListView { get; set; }

        /// <summary>
        /// Drops the specified e.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.DragEventArgs"/> instance containing the event data.</param>
        public void Drop(DragEventArgs e)
        {
            e.Effects = DragDropEffects.Copy;
            var container = e.Data.GetData(typeof(DragDropContainer)) as DragDropContainer;
            var cell = ((FrameworkElement)e.OriginalSource).GetNearestVisualParent<DataGridCell>();
            var row = ((FrameworkElement)e.OriginalSource).GetNearestVisualParent<DataGridRow>();
            if (container == null || row == null || cell == null)
            {
                e.Effects = DragDropEffects.None;
                return;
            }

            var column = cell.Column;
            var args = ListView.ColumnPropertyRelation[column];
            var genericArgs = args.PropertyType.GetGenericArguments();
            if (genericArgs.Length == 0 || genericArgs[0] != container.ItemType)
            {
                e.Effects = DragDropEffects.None;
                return;
            }

            var item = row.Item;
            var property =
                item.GetType().GetProperties().FirstOrDefault(p => p.PropertyType == args.PropertyType);
            var value = property.GetValue(item);
            var method = value.GetType().GetMethod("Add");
            if (property == null || method == null)
            {
                e.Effects = DragDropEffects.None;
                return;
            }

            foreach (var i in container.Items)
            {
                method.Invoke(value, new[] { i });
            }

            row.BindingGroup.UpdateSources();
        }

        /// <summary>
        /// Drags the specified data grid.
        /// </summary>
        public void Drag()
        {
            var dataGrid = ListView.ItemsDataGrid;
            var selectedItems = new List<object>();
            foreach (var cell in dataGrid.SelectedCells)
            {
                if (!selectedItems.Contains(cell.Item))
                {
                    selectedItems.Add(cell.Item);
                }
            }

            var container = new DragDropContainer
                                {
                                    ItemType = dataGrid.ItemsSource.GetType().GetGenericArguments()[0],
                                    Items = selectedItems,
                                };
            DragDrop.DoDragDrop(dataGrid, container, DragDropEffects.Copy);
        }
    }
}
